#include "event_sqlite_storage.h"
#include <sstream>
#include "utils_log.h"
#include "common_event.h"
#include "utils_file_ex.h"

namespace El {
namespace Event {

IStorage &IStorage::GetInstance()
{
    static SqliteStorage instance;
    return instance;
}

SqliteStorage::SqliteStorage() : db_(nullptr), insert_stmt_(nullptr), query_stmt_(nullptr), max_events_(1000) {}

SqliteStorage::~SqliteStorage()
{
    close_db();
}

void SqliteStorage::close_db()
{
    if (query_stmt_) {
        sqlite3_finalize(query_stmt_);
        query_stmt_ = nullptr;
    }
    if (insert_stmt_) {
        sqlite3_finalize(insert_stmt_);
        insert_stmt_ = nullptr;
    }
    if (db_) {
        sqlite3_close(db_);
        db_ = nullptr;
    }
}

bool SqliteStorage::deinit()
{
    std::lock_guard<std::mutex> lock(mutex_);
    close_db();
    return true;
}

bool SqliteStorage::init(const nlohmann::json &config)
{
    std::lock_guard<std::mutex> lock(mutex_);

    try {
        if (!config.contains("db_path")) {
            EL_ERROR("Missing required configuration: db_path");
            return false;
        }

        db_path_ = config["db_path"].get<std::string>();

        if (config.contains("max_events")) {
            max_events_ = config["max_events"].get<size_t>();
            if (max_events_ == 0) {
                EL_ERROR("Invalid max_events value: must be greater than 0");
                return false;
            }
        }

        // 获取数据库目录路径
        std::string db_dir = El::Utils::ExtractFilePath(db_path_);
        
        // 创建目录（如果不存在）
        if (!El::Utils::CreateDirectories(db_dir)) {
            EL_ERROR("Failed to create database directory: {}", db_dir);
            return false;
        }

        // 检查目录是否可写
        if (access(db_dir.c_str(), W_OK) != 0) {
            EL_ERROR("Database directory is not writable: {}", db_dir);
            return false;
        }

        // Open database
        int rc = sqlite3_open(db_path_.c_str(), &db_);
        if (rc) {
            EL_ERROR("Failed to open database: {}", sqlite3_errmsg(db_));
            return false;
        }

        // 设置 Journal 模式为 DELETE
        sqlite3_exec(db_, "PRAGMA journal_mode=DELETE;", nullptr, nullptr, nullptr);

        // 设置同步级别为 FULL
        sqlite3_exec(db_, "PRAGMA synchronous=FULL;", nullptr, nullptr, nullptr);

        // 可选：设置锁定模式为 EXCLUSIVE
        sqlite3_exec(db_, "PRAGMA locking_mode=EXCLUSIVE;", nullptr, nullptr, nullptr);

        // Create tables
        if (!create_tables()) {
            EL_ERROR("Failed to create tables");
            close_db();
            return false;
        }

        // Prepare statements
        if (!prepare_statements()) {
            EL_ERROR("Failed to prepare statements");
            close_db();
            return false;
        }

        return true;
    } catch (const std::exception &) {
        close_db();
        EL_ERROR("exception");
        return false;
    }
}

bool SqliteStorage::create_tables()
{
    const char *sql =
        "CREATE TABLE IF NOT EXISTS events ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    event_type TEXT NOT NULL,"
        "    timestamp INTEGER NOT NULL,"
        "    status TEXT NOT NULL,"
        "    channel INTEGER,"
        "    region_id TEXT,"
        "    data TEXT NOT NULL"
        ");"
        "CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);"
        "CREATE INDEX IF NOT EXISTS idx_events_event_type ON events(event_type);";

    char *err_msg = nullptr;
    int rc = sqlite3_exec(db_, sql, nullptr, nullptr, &err_msg);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to create tables: {}", err_msg ? err_msg : "unknown error");
        sqlite3_free(err_msg);
        return false;
    }

    return true;
}

bool SqliteStorage::prepare_statements()
{
    // 准备插入语句
    const char *insert_sql =
        "INSERT INTO events (event_type, timestamp, status, "
        "channel, region_id, data) "
        "VALUES (?, ?, ?, ?, ?, ?);";

    int rc = sqlite3_prepare_v2(db_, insert_sql, -1, &insert_stmt_, nullptr);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to prepare insert statement: {}", sqlite3_errmsg(db_));
        return false;
    }

    // 修改查询语句，支持空时间范围和空字符串返回所有类型
    const char *query_sql =
        "SELECT id, event_type, timestamp, status, channel, region_id, data "
        "FROM events "
        "WHERE ((? = 0 AND ? = 0) OR (timestamp >= ? AND timestamp <= ?)) "
        "AND (? = '' OR event_type = ?);";

    rc = sqlite3_prepare_v2(db_, query_sql, -1, &query_stmt_, nullptr);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to prepare query statement: {}", sqlite3_errmsg(db_));
        return false;
    }

    return true;
}

bool SqliteStorage::store(const nlohmann::json &event_data)
{
    try {
        // Validate required fields
        if (!event_data.contains("event_type") || !event_data.contains("timestamp") || !event_data.contains("status")) {
            EL_ERROR("Missing required fields in event data");
            return false;
        }

        std::lock_guard<std::mutex> lock(mutex_);

        // 检查事件数量是否达到最大限制
        if (count() >= max_events_) {
            // 删除最早的一条记录
            const char *delete_sql = "DELETE FROM events WHERE id IN (SELECT id FROM events ORDER BY timestamp ASC LIMIT 1);";
            char *err_msg = nullptr;
            int rc = sqlite3_exec(db_, delete_sql, nullptr, nullptr, &err_msg);
            if (rc != SQLITE_OK) {
                EL_ERROR("Failed to delete oldest event: {}", err_msg ? err_msg : "unknown error");
                sqlite3_free(err_msg);
                return false;
            }
        }

        sqlite3_clear_bindings(insert_stmt_);

        // 修改绑定方式，确保使用 SQLITE_TRANSIENT
        const std::string event_type = event_data["event_type"].get<std::string>();
        int rc = sqlite3_bind_text(insert_stmt_, 1, event_type.c_str(), -1, SQLITE_TRANSIENT);
        if (rc != SQLITE_OK) {
            EL_ERROR("Failed to bind event_type: {}", sqlite3_errmsg(db_));
            return false;
        }

        rc = sqlite3_bind_int64(insert_stmt_, 2, event_data["timestamp"].get<int64_t>());
        if (rc != SQLITE_OK) {
            EL_ERROR("Failed to bind timestamp: {}", sqlite3_errmsg(db_));
            return false;
        }

        rc = sqlite3_bind_text(insert_stmt_, 3, event_data["status"].get<std::string>().c_str(), -1, SQLITE_TRANSIENT);
        if (rc != SQLITE_OK) {
            EL_ERROR("Failed to bind status: {}", sqlite3_errmsg(db_));
            return false;
        }

        // Optional source fields
        if (event_data.contains("source") && event_data["source"].contains("channel")) {
            rc = sqlite3_bind_int(insert_stmt_, 4, event_data["source"]["channel"].get<int>());
        } else {
            rc = sqlite3_bind_null(insert_stmt_, 4);
        }
        if (rc != SQLITE_OK) {
            EL_ERROR("Failed to bind channel: {}", sqlite3_errmsg(db_));
            return false;
        }

        if (event_data.contains("source") && event_data["source"].contains("region_id")) {
            const std::string region_id = event_data["source"]["region_id"].get<std::string>();
            rc = sqlite3_bind_text(insert_stmt_, 5, region_id.c_str(), -1, SQLITE_TRANSIENT);
        } else {
            rc = sqlite3_bind_null(insert_stmt_, 5);
        }
        if (rc != SQLITE_OK) {
            EL_ERROR("Failed to bind region_id: {}", sqlite3_errmsg(db_));
            return false;
        }

        // Store complete event data
        const std::string data_str = event_data.dump();
        rc = sqlite3_bind_text(insert_stmt_, 6, data_str.c_str(), -1, SQLITE_TRANSIENT);
        if (rc != SQLITE_OK) {
            EL_ERROR("Failed to bind data: {}", sqlite3_errmsg(db_));
            return false;
        }

        // Execute
        rc = sqlite3_step(insert_stmt_);
        if (rc != SQLITE_DONE) {
            EL_ERROR("Failed to execute insert: {}", sqlite3_errmsg(db_));
            sqlite3_reset(insert_stmt_);
            return false;
        }

        sqlite3_reset(insert_stmt_);
        return true;
    } catch (const std::exception &e) {
        EL_ERROR("Failed to store event data: {}", e.what());
        sqlite3_reset(insert_stmt_);
        return false;
    }
}

std::vector<nlohmann::json> SqliteStorage::query(int64_t start_time, int64_t end_time, const std::string &event_type)
{
    std::lock_guard<std::mutex> lock(mutex_);
    std::vector<nlohmann::json> results;

    if (!query_stmt_) {
        EL_ERROR("Query statement not prepared");
        return results;
    }

    sqlite3_reset(query_stmt_);
    sqlite3_clear_bindings(query_stmt_);

    // 绑定时间范围参数（用于判断是否为空时间范围）
    int rc = sqlite3_bind_int64(query_stmt_, 1, start_time);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to bind start_time (1): {}", sqlite3_errmsg(db_));
        return results;
    }

    rc = sqlite3_bind_int64(query_stmt_, 2, end_time);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to bind end_time (1): {}", sqlite3_errmsg(db_));
        return results;
    }

    // 绑定时间范围参数（用于实际查询）
    rc = sqlite3_bind_int64(query_stmt_, 3, start_time);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to bind start_time (2): {}", sqlite3_errmsg(db_));
        return results;
    }

    rc = sqlite3_bind_int64(query_stmt_, 4, end_time);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to bind end_time (2): {}", sqlite3_errmsg(db_));
        return results;
    }

    // 绑定event_type
    rc = sqlite3_bind_text(query_stmt_, 5, event_type.c_str(), -1, SQLITE_TRANSIENT);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to bind event_type (1): {}", sqlite3_errmsg(db_));
        return results;
    }

    rc = sqlite3_bind_text(query_stmt_, 6, event_type.c_str(), -1, SQLITE_TRANSIENT);
    if (rc != SQLITE_OK) {
        EL_ERROR("Failed to bind event_type (2): {}", sqlite3_errmsg(db_));
        return results;
    }

    while ((rc = sqlite3_step(query_stmt_)) == SQLITE_ROW) {
        const char *json_str = reinterpret_cast<const char *>(sqlite3_column_text(query_stmt_, 6));
        if (json_str) {
            try {
                results.push_back(nlohmann::json::parse(json_str));
            } catch (const nlohmann::json::parse_error &e) {
                EL_ERROR("Failed to parse JSON: {}", e.what());
            }
        }
    }

    if (rc != SQLITE_DONE) {
        EL_ERROR("Query failed: {}", sqlite3_errmsg(db_));
    }

    sqlite3_reset(query_stmt_);
    return results;
}

int SqliteStorage::delete_events(int64_t start_time, int64_t end_time, const std::string &event_type)
{
    std::string sql = "DELETE FROM events WHERE timestamp >= ? AND timestamp <= ?";

    if (!event_type.empty()) {
        sql += " AND event_type = ?";
    }

    sqlite3_stmt *stmt = nullptr;
    int rc = sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        return 0;
    }

    sqlite3_bind_int64(stmt, 1, start_time);
    sqlite3_bind_int64(stmt, 2, end_time);

    if (!event_type.empty()) {
        sqlite3_bind_text(stmt, 3, event_type.c_str(), -1, SQLITE_STATIC);
    }

    rc = sqlite3_step(stmt);
    sqlite3_finalize(stmt);

    if (rc != SQLITE_DONE) {
        return 0;
    }

    return sqlite3_changes(db_);
}

size_t SqliteStorage::count() const
{
    std::lock_guard<std::mutex> lock(mutex_);

    sqlite3_stmt *stmt = nullptr;
    const char *sql = "SELECT COUNT(*) FROM events;";

    size_t count = 0;

    int rc = sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr);
    if (rc == SQLITE_OK) {
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            count = static_cast<size_t>(sqlite3_column_int64(stmt, 0));
        }
        sqlite3_finalize(stmt);
    }

    return count;
}

// Factory function implementation
std::unique_ptr<IStorage> create_storage(const std::string &storage_type, const nlohmann::json &config)
{
    if (storage_type == "sqlite") {
        auto storage = std::make_unique<SqliteStorage>();
        if (storage->init(config)) {
            return storage;
        }
    }
    return nullptr;
}

} // namespace Event
} // namespace El
